#!/usr/bin/env python
# -*- coding: utf-8 -*-

import datetime

from farado.logger import logger
from farado.general_manager_holder import gm_holder
from farado.items.issue import Issue
from farado.items.issue_change import IssueChange
from farado.helpers.long_action_watcher import LongActionHandler


class IssueStatisticsHelper(LongActionHandler):

    class IssueStateData:
        def __init__(
                self,
                issue_id=None,
                state_id=None,
                next_state_id=None,
                user_id=None,
                timedelta=None) -> None:
            self.issue_id = issue_id
            self.state_id = state_id
            self.next_state_id = next_state_id
            self.user_id = user_id
            self.timedelta = timedelta

    #--------------------------------------------------------------------------#
    def issue_states_data(self, issue):
        result = []
        if not issue or not issue.changes:
            return result

        creation = issue.changes[0]
        last_user_id = creation.user_id
        last_date_time = creation.date_time

        for change in issue.ordered_changes():
            old_state_id, new_state_id = states_from_issue_change(change)
            if not old_state_id or not new_state_id:
                continue

            result.append(
                IssueStatisticsHelper.IssueStateData(
                    issue_id=issue.id,
                    state_id=old_state_id,
                    next_state_id=new_state_id,
                    user_id=last_user_id,
                    timedelta=subtract_datetime(
                        current=change.date_time,
                        before=last_date_time
                    )
                )
            )
            last_user_id = change.user_id
            last_date_time = change.date_time

        result.append(
            IssueStatisticsHelper.IssueStateData(
                issue_id=issue.id,
                state_id=issue.state_id,
                user_id=last_user_id,
                timedelta=(datetime.datetime.now() - last_date_time)
            )
        )
        return result

    #--------------------------------------------------------------------------#
    def employees_ids(self, issue):
        if not issue:
            return []
        issues = gm_holder.project_manager.sub_issues(issue.id)
        if not issues:
            issues = [issue]
        result = set()
        for issue in issues:
            for item in self.issue_states_data(issue):
                result.add(item.user_id)
        return [item for item in result]

    #--------------------------------------------------------------------------#
    def is_active_issue(self, issue):
        if not issue:
            return False
        issues = gm_holder.project_manager.sub_issues(issue.id)
        if not issues:
            issues = [issue]
        for issue in issues:
            if state := gm_holder.project_manager.state(issue.state_id):
                if state.is_active():
                    return True
        return False

    class EmployeeTimeData:
        def __init__(
                self,
                employee_id=None,
                percentage=None,
                timedelta=None) -> None:
            self.employee_id = employee_id
            self.percentage = percentage
            self.timedelta = timedelta

    #--------------------------------------------------------------------------#
    def employee_time_data(self, issue):
        if not issue:
            return []
        issues = gm_holder.project_manager.sub_issues(issue.id)
        if not issues:
            issues = [issue]
        employee_time = {}
        for issue in issues:
            for item in self.issue_states_data(issue):
                state = gm_holder.project_manager.state(item.state_id)
                next_state = gm_holder.project_manager.state(item.next_state_id)
                if not state:
                    continue
                weight_percentage = state.weight_percentage()
                if 0 == weight_percentage or 100 == weight_percentage:
                    continue
                if next_state := gm_holder.project_manager.state(item.next_state_id):
                    if weight_percentage == next_state.weight_percentage():
                        continue
                if not item.user_id in employee_time:
                    employee_time[item.user_id] = datetime.timedelta(0)
                employee_time[item.user_id] += item.timedelta
        result = []
        times_sum = sum([item.total_seconds() for item in employee_time.values()])
        if 0 == times_sum:
            return []
        for employee_id, time in employee_time.items():
            result.append(
                IssueStatisticsHelper.EmployeeTimeData(
                    employee_id=employee_id,
                    percentage=round(time.total_seconds() * 100 / times_sum),
                    timedelta=time
                )
            )
        return sorted(
            result,
            reverse=True,
            key=lambda item: item.percentage)

def old_id_form_diff(diff):
    return id_form_diff(diff, value_startswith='-')

def new_id_form_diff(diff):
    return id_form_diff(diff, value_startswith='+')

def id_form_diff(diff, value_startswith):
    if not type(diff) == dict:
        return None

    for id, value in diff.items():
        if not type(value) == str:
            continue

        if value.startswith(value_startswith):
            return id

    return None

def subtract_datetime(current, before):
    # TODO : Учесть выходные и праздники.
    return current - before

def states_from_issue_change(change):
    if not change:
        return (None, None)

    diff = change.dict_diff()
    if not IssueChange.DiffKey.state in diff:
        return (None, None)

    state_diff = diff[IssueChange.DiffKey.state]
    old_state_id = old_id_form_diff(state_diff)
    new_state_id = new_id_form_diff(state_diff)
    return (old_state_id, new_state_id)
